package com.celebriosoftware.client.fragments;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.CookieManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.celebriosoftware.celebrioclient.R;
import com.celebriosoftware.client.BrowserActivity;
import com.celebriosoftware.client.MainActivity;
import com.celebriosoftware.client.listener.MyPhoneStateListener;
import com.celebriosoftware.client.receiver.BatteryReceiver;
import com.celebriosoftware.client.receiver.WifiReceiver;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class DesktopFragment extends Fragment {
	private MainActivity mainActivity;
	private BatteryReceiver batteryReceiver;
	private WifiReceiver wifiReceiver;
	private MyPhoneStateListener gsmListener;
	private TelephonyManager phone;
	public final static String DESKTOP_APPS_URL=MainActivity.CELEBRIO_URL+"/default/getapps?background=true";
	AsyncTask<Void, Void, JSONObject> getAppsTask;
	private static JSONArray appsJSON=null;	//Stores app list
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mainActivity=(MainActivity) this.getActivity();
		gsmListener = new MyPhoneStateListener(this);
	    phone = ( TelephonyManager )mainActivity.getSystemService(Context.TELEPHONY_SERVICE);
		phone.listen(gsmListener ,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
	}
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		return inflater.inflate(R.layout.desktop, container, false);
	}
	@Override
	public void onDestroyView() {
		getAppsTask.cancel(true);
		super.onDestroyView();
	}
	@SuppressLint("NewApi")
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);
		//Set clocks font
		((TextView) getView().findViewById(R.id.clock)).setTypeface(Typeface.createFromAsset(mainActivity.getAssets(), "fonts/XXII-SinozDSP_Regular.otf"));
		//Set background if it's remembered
		if(MainActivity.background!=null) {
			if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
				getView().getRootView().findViewById(R.id.MainLayout).setBackgroundDrawable(MainActivity.background);
			} else {
				getView().getRootView().findViewById(R.id.MainLayout).setBackground(MainActivity.background);
			}
		}
		//Show apps
		if(appsJSON!=null && MainActivity.backgroundIsOK) {
			buildAppViews(appsJSON);
		}
		else {
			//Load apps from server
			getAppsTask=new getAppsJSON();
			getAppsTask.execute();
		}
		View feedbackButton = (View) getView().findViewById(R.id.feedback);
		feedbackButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mainActivity.startApp(MainActivity.CELEBRIO_URL+"/app/feedback/",101, getString(R.string.feedback));
			}
		});
		View logoutButton = (View) getView().findViewById(R.id.logout);
		logoutButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("celebrio-android", "exiting celebrio");
				mainActivity.finish();
			}
		});
	}
	
	@Override
	public void onStart() {
		super.onStart();
	}
	
	@Override
	public void onResume() {
		super.onResume();
		
		batteryReceiver = new BatteryReceiver(this);
		IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
		mainActivity.registerReceiver(batteryReceiver, filter);
		
		wifiReceiver = new WifiReceiver(this);
		IntentFilter wifiFilter = new IntentFilter(WifiManager.RSSI_CHANGED_ACTION);
		mainActivity.registerReceiver(wifiReceiver, wifiFilter);
		
		phone.listen(gsmListener ,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
		
		updateVolume(mainActivity.getSpeakerState());
	}
	
	@Override
	public void onPause() {
		super.onPause();
		mainActivity.unregisterReceiver(batteryReceiver);
		mainActivity.unregisterReceiver(wifiReceiver);
	    phone.listen(gsmListener, PhoneStateListener.LISTEN_NONE);
	}
	
	/*
	 * Get apps list from server
	 */
	private class getAppsJSON extends AsyncTask<Void, Void, JSONObject> {
		protected JSONObject doInBackground(Void... voids) {
			HttpGet request = new HttpGet(DESKTOP_APPS_URL);
			
			CookieManager cm=CookieManager.getInstance();
			request.setHeader("Cookie", cm.getCookie(MainActivity.CELEBRIO_URL));

			//Must send header that we are android, so that server gives us specific android apps (browser,...), too.
			String clientVersion = "unknown";	
			try
			{
				clientVersion = mainActivity.getPackageManager().getPackageInfo(mainActivity.getPackageName(), 0).versionName;
			}
			catch (NameNotFoundException e)
			{
			    Log.e("Celebrio-Version", e.getMessage());
			}
			DisplayMetrics metrics = mainActivity.getResources().getDisplayMetrics();
			String userAgent = "Native android http request; "+ MainActivity.CELEBRIO_CLIENT
					+ "/" + clientVersion + "; dpi/" + metrics.densityDpi
					+ "; res-width/" + metrics.widthPixels + "; res-height/"
					+ metrics.heightPixels + ";)";
		
			Log.i("Celebrio-UserAgent", userAgent);
			request.setHeader("User-Agent", userAgent);
			HttpParams httpParameters = new BasicHttpParams();
			HttpConnectionParams.setConnectionTimeout(httpParameters, 10000);
			HttpClient httpClient = new DefaultHttpClient();
			
			HttpResponse response=null;
			JSONObject json=null;
			try {
				response = httpClient.execute(request);
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(response!=null) {
				int status = response.getStatusLine().getStatusCode();
				if (status != HttpStatus.SC_OK) {
					Log.e("celebrio-client", "Http not returned 200, did "+String.valueOf(status));
					return null;
				}
				HttpEntity entity = response.getEntity();
			
				StringBuilder responseStrBuilder = new StringBuilder();
				
				if (entity != null) {
					InputStream instream;
					try {
						instream = entity.getContent();
						try {
					        BufferedReader streamReader = new BufferedReader(new InputStreamReader(instream)); 
					        String inputStr;
					        while ((inputStr = streamReader.readLine()) != null) {
					            responseStrBuilder.append(inputStr);
					        }
					    } catch (IOException ex) {
					        // In case of an IOException the connection will be released
					        // back to the connection manager automatically
					        ex.printStackTrace();
					    } catch (RuntimeException ex) {
					        // In case of an unexpected exception you may want to abort
					        // the HTTP request in order to shut down the underlying
					        // connection and release it back to the connection manager.
					    	request.abort();
					        throw ex;
					    } finally {
					        // Closing the input stream will trigger connection release
					    	instream.close();
					    }
					} catch (IllegalStateException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					};

				}
				httpClient.getConnectionManager().shutdown();
				
				try {
					json = new JSONObject(responseStrBuilder.toString());
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}
			return json;
	    }
	     
	    @SuppressLint("NewApi")
		protected void onPostExecute(JSONObject apps) {
			if(apps!=null) {
				try {
					appsJSON = (JSONArray) apps.get("apps");
					String url=apps.getString("background");
					if(!url.equals(MainActivity.backgroundURL)) {
						MainActivity.backgroundURL = url;
						(new getImageFromUrl() {
							protected void onPostExecute(Drawable d) {
								MainActivity.background=d;
								if(MainActivity.background==null) {
									return;
								}
								if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
									getView().getRootView().findViewById(R.id.MainLayout).setBackgroundDrawable(MainActivity.background);
								} else {
									getView().getRootView().findViewById(R.id.MainLayout).setBackground(MainActivity.background);
								}
								MainActivity.backgroundIsOK=true;
							};
						}).execute(url);
					}
					else {
						MainActivity.backgroundIsOK=true;
					}
				} catch (JSONException e) {
					e.printStackTrace();
				}
				buildAppViews(appsJSON);
			}
			else {
				Log.e("celebrio-client", "Null JSON received. Cannot load apps.");
			}
	    }
	}
	
	//To be able to generate unique View id's
	public static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
	/**
	 * Generate a value suitable for use in {@link #setId(int)}.
	 * This value will not collide with ID values generated at build time by aapt for R.id.
	 *
	 * @return a generated ID value
	 */
	public static int generateViewId() {
	    for (;;) {
	        final int result = sNextGeneratedId.get();
	        // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
	        int newValue = result + 1;
	        if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
	        if (sNextGeneratedId.compareAndSet(result, newValue)) {
	            return result;
	        }
	    }
	}

	private abstract class getImageFromUrl extends AsyncTask<String, Void, Drawable> {
		protected Drawable doInBackground(String... args) {
	        URL url=null;
			try {
				url = new URL(args[0]);
				return Drawable.createFromStream((InputStream) url.getContent(), "src");
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
	    }
		@Override
		protected abstract void onPostExecute(Drawable result);
	}
	
	
	//Used by getIconFromUrl to pass return values
	private class Container2 {
		public int id;
		public ImageView view;
	}	
	/*
	 * Used to get icon from web and set it to given imageview
	 * arguments - Object array
	 * first: int id of the app
	 * second: imageview to which a picture will be set
	 * third: drawable to be saved
	 */
	private class getIconFromUrl extends AsyncTask<Object, Void, Container2> {
		protected Container2 doInBackground(Object... args) {
	        URL url=null;
	        int appId;
			try {
				appId = (Integer) args[0];
				url = new URL((String) args[2]);

				InputStream content=null;
				content = (InputStream) url.getContent();
				//Save drawable to appsIcons SparseArray field
				MainActivity.appsIcons.put(appId, Drawable.createFromStream(content, "src"));
				
				Container2 c=new Container2();
				c.id=appId;
				c.view=(ImageView) args[1];
				
				return c;

			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
	    }
	     
	    protected void onPostExecute(Container2 c) {
	    	c.view.setImageDrawable(MainActivity.appsIcons.get(c.id));
	    	if(numRequests.decrementAndGet()<=0) {
	    		mainActivity.removeSplashScreen();
	    		mainActivity.removeLoadingDialog();
	    	}
	    }
	}
	
	//To be able to generate unique View id's
	public static final AtomicInteger numRequests = new AtomicInteger(0);
	//Parses JSON and creates Views for apps icons and labels on desktop
	private View buildAppViews(JSONArray apps) {
		if(getView()==null) return null;
		RelativeLayout appsContainer = (RelativeLayout) getView().findViewById(R.id.desktop_apps_container);
		Integer lastAppId=null;
		numRequests.set(apps.length());
		for(int i=0;i<apps.length();i++) {
			try {
				JSONObject app = (JSONObject) apps.get(i);
				//Container
				RelativeLayout thisAppContainer = new RelativeLayout(mainActivity);
				RelativeLayout.LayoutParams params = (new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
				params.setMargins(50,0,50,0);
				if(lastAppId!=null) {
					params.addRule(RelativeLayout.RIGHT_OF, lastAppId);
				}
				thisAppContainer.setLayoutParams(params);
				thisAppContainer.setId(generateViewId());
				//Icon
				ImageView thisAppIcon=new ImageView(mainActivity);
				int appId=app.getInt("id");
				Drawable icon = MainActivity.appsIcons.get(appId);
				if(icon!=null) {
					thisAppIcon.setImageDrawable(icon);
					numRequests.decrementAndGet();
				}
				else {
					(new getIconFromUrl()).execute(new Object[]{ appId, thisAppIcon, app.getString("icon") });
				}
				RelativeLayout.LayoutParams imgParams=new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
				imgParams.bottomMargin=20;
				imgParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
				thisAppIcon.setLayoutParams(imgParams);
				thisAppIcon.setId(generateViewId());
				thisAppContainer.addView(thisAppIcon);
				//Button
				Button thisAppButton = new Button(mainActivity);
				RelativeLayout.LayoutParams buttonParams = (new RelativeLayout.LayoutParams(300, LayoutParams.WRAP_CONTENT));
				buttonParams.addRule(RelativeLayout.BELOW, thisAppIcon.getId());
				buttonParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
				thisAppButton.setLayoutParams(buttonParams);
				thisAppButton.setGravity(Gravity.CENTER);
				thisAppButton.setClickable(false);
				thisAppButton.setText(app.getString("title"));
				thisAppButton.setTextSize(40);
				thisAppButton.setTypeface(Typeface.createFromAsset(mainActivity.getAssets(), "fonts/XXII-SinozDSP_Regular.otf"));
				thisAppContainer.addView(thisAppButton);
				
				//Internet opens our native browser
				if(app.getString("name").equals("Internet")) {
					//OnClick for the whole container
					thisAppContainer.setOnClickListener(
						new OnClickListener() {
							@Override
							public void onClick(View v) {
								Intent startNewActivityOpen = new Intent(mainActivity,BrowserActivity.class);
								startNewActivityOpen.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
								startNewActivityOpen.putExtra("com.celebriosoftware.client.uri", MainActivity.BROWSER_DEFAULT_URL);
								startNewActivityOpen.putExtra("com.celebriosoftware.client.userlang", "cs");
								mainActivity.startActivity(startNewActivityOpen);
							}
						}
					);	
				}
				else {//the rest loads app from server on click
					//OnClick for the whole container
					class OurOnClickListener implements OnClickListener {
						private String url;
						private int appId;
						private String appLabel;
						public OurOnClickListener(String url, int appId, String appLabel) {
							this.url=url;
							this.appId=appId;
							this.appLabel=appLabel;
						}
						
						@Override
						public void onClick(View v) {
							//mainActivity.showLoadingDialog(appLabel, MainActivity.appsIcons.get(appId));
							mainActivity.startApp(url, appId, appLabel);
						}				
					}
					thisAppContainer.setOnClickListener(new OurOnClickListener(app.getString("url"),app.getInt("id"),app.getString("title")));					
				}
				appsContainer.addView(thisAppContainer);
				lastAppId=thisAppContainer.getId();
				if(numRequests.get()<=0) {
		    		mainActivity.removeSplashScreen();
		    		mainActivity.removeLoadingDialog();
				}
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return appsContainer;
	}
	
	public void updateBatteryState(int state) {
		ImageView imageView=(ImageView) getView().findViewById(R.id.battery);
		switch (state) {
		case -1:
			imageView.setImageResource(R.drawable.battery_empty);
			break;
		case 1:
			imageView.setImageResource(R.drawable.battery_1);
			break;
		case 2:
			imageView.setImageResource(R.drawable.battery_2);
			break;
		case 3:
			imageView.setImageResource(R.drawable.battery_3);
			break;
		case 4:
			imageView.setImageResource(R.drawable.battery_4);
			break;
		default:
			imageView.setImageResource(R.drawable.battery_0);
			break;
		}
	}
	public void updateWifiState(int state) {
		ImageView imageView=(ImageView) getView().findViewById(R.id.wifi);
		switch (state) {
		case 1:
			imageView.setImageResource(R.drawable.wifi_1);
			break;
		case 2:
			imageView.setImageResource(R.drawable.wifi_2);
			break;
		case 3:
			imageView.setImageResource(R.drawable.wifi_3);
			break;
		default:
			imageView.setImageResource(R.drawable.wifi_0);
			break;
		}
	}
	public void updateGSMState(int state) {
		ImageView imageView=(ImageView) getView().findViewById(R.id.antenna);
		switch (state) {
		case 1:
			imageView.setImageResource(R.drawable.antenna_1);
			break;
		case 2:
			imageView.setImageResource(R.drawable.antenna_2);
			break;
		case 3:
			imageView.setImageResource(R.drawable.antenna_3);
			break;
		case 4:
			imageView.setImageResource(R.drawable.antenna_4);
			break;
		default:
			imageView.setImageResource(R.drawable.antenna_0);
			break;
		}
	}
	public void updateVolume(int state) {
		ImageView imageView=(ImageView) getView().findViewById(R.id.speaker);
		switch (state) {
		case 1:
			imageView.setImageResource(R.drawable.speaker_1);
			break;
		case 2:
			imageView.setImageResource(R.drawable.speaker_2);
			break;
		case 3:
			imageView.setImageResource(R.drawable.speaker_3);
			break;
		case 4:
			imageView.setImageResource(R.drawable.speaker_4);
			break;
		default:
			imageView.setImageResource(R.drawable.speaker_0);
			break;
		}
	}
}
